#include "Connection.h"
#include <sys/syscall.h>

Connection::Connection(EventLoop* loop, std::unique_ptr <Socket> clientSock)
:loop_(loop),client_sock_(std::move(clientSock)),disconnect_(false),client_Channel_(new Channel(loop_, client_sock_->fd()))
{
    //创建一个Channel对象
    //client_Channel_ = new Channel(loop_, client_sock_->fd());
    //设置回调函数
    client_Channel_->set_Read_CallBack(std::bind(&Connection::on_Message, this));
    client_Channel_->set_Close_CallBack(std::bind(&Connection::closeCallback, this));
    client_Channel_->set_Error_CallBack(std::bind(&Connection::errorCallback, this));
    client_Channel_->set_Write_CallBack(std::bind(&Connection::writeCallback, this));
    client_Channel_->useet();//设置为边缘触发
    //将对象的设置为可读事件，并将事件和fd加入红黑树
    client_Channel_->enable_Reading();
}

Connection::~Connection()
{
    // printf("conn已析构\n");
}

int Connection::fd() const
{
    return client_sock_->fd();
}

std::string Connection::ip() const
{
    return client_sock_->ip();
}

uint16_t Connection::port() const
{
    return client_sock_->port();
} 

void Connection::closeCallback()       //TCP连接关闭(断开)的回调函数，供Channel回调
{
    disconnect_ = true;
    client_Channel_->remove();      //从事件循环中删除channel
    close_CallBack(shared_from_this());//shared_from_this()返回this的智能指针
}

void Connection::errorCallback()       //TCP连接错误的回调函数，供Channel回调
{
    disconnect_ = true;
    client_Channel_->remove();      //从事件循环中删除channel
    error_CallBack(shared_from_this());
}

void Connection::writeCallback()        //处理写事件的回调函数，供channel回调
{
    //将发送缓存区的数据发出去
    int write_n = ::send(fd(),output_buffer_.data(), output_buffer_.size(), 0);
    if(write_n > 0)
    {
        output_buffer_.erase(0, write_n);   //清除已发送的字节
    }

    //发送缓存区已经发送完毕
    if(output_buffer_.size() == 0)
    {
        send_Complete_CallBack(shared_from_this());
        client_Channel_->disable_Writing(); //停止关注写事件
    }
}
void Connection::set_closeCallBack(std::function<void(spConnection)> func)
{
    close_CallBack = func;
}

void Connection::set_errorCallBack(std::function<void(spConnection)> func)
{
    error_CallBack = func;
}

void Connection::set_onMessageCallBack(std::function<void(spConnection, std::string&)> func)
{
    on_Message_CallBack = func;
}

void Connection::set_sendCompleteCallBack(std::function<void(spConnection)> func)
{
    send_Complete_CallBack = func;
}

void Connection::on_Message()                              //处理对端发来的消息
{
    char buffer[1024];
    while(true)
    {
        bzero(&buffer, sizeof(buffer));
        ssize_t nread = read(fd(), buffer,  sizeof(buffer));
        if(nread > 0)   //成功的读取到了数据,放入接收缓冲区
        {
            input_buffer_.append(buffer, nread);
        }
        else if(nread == -1 && errno == EINTR) //读取数据
        {
            continue;
        }
        else if(nread == -1 && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))//全部的数据读取完毕。
        {
            std::string message;

            //全部接收完毕，发送
            while(true)
            {
                if(input_buffer_.pickMessage(message) == false) break;
                //printf("recv(eventfd = %d):%s\n", fd(), message.c_str());
                lasttime_ = Timestamp::now();       //更新Connection的时间戳
                //std::cout << "lasttime = " << lasttime_.toString() << std::endl;
                on_Message_CallBack(shared_from_this(), message); //回调TcpServer::onMessage()
            } 
            
            break;
        }
        else if(nread == 0)//客户端已经断开连接
        {

            closeCallback();    //回调TcpServer::closeConnection()
            break;
        }
    }
}

//发送数据
void Connection::send(const char* data, size_t size)//这里的data为局部变量
{
    if(disconnect_ == true)
    {
        printf("客户端连接已断开, send()直接返回\n");
        return;
    }

    if(loop_->isInLoopThread())//判断当前线程是否为事件循环线程(IO线程)
    {
        //如果当前是IO线程，直接执行发送数据的操作
        // printf("send() 在事件循环的线程中\n");
        sendInLoop(data, size);
    }
    else
    {
        //如果当前不是IO线程，把发送数据的操作交给IO线程去执行
        // printf("send() 不在事件循环的线程中\n");
        loop_->queueInLoop(std::bind(&Connection::sendInLoop, this, data, size));
    }
}

//发送数据，如果当前线程是IO线程，直接调用此函数，如果是工作线程，将把此函数传给IO线程
void Connection::sendInLoop(const char* data, size_t size)
{
    output_buffer_.appendWithSep(data, size);  //把需要发送的数据保存到发送缓存区
    client_Channel_->enbale_Writing();  //注册写事件
}

//判断Tcp连接是否超时
bool Connection::timeOut(time_t now, int val)
{
    return now - lasttime_.toint() > val;
}